﻿// <copyright file="WebServerCore.cs" company="Maierhofer Software">
//      Copyright (c) 2010 by Maierhofer Software. All rights reserved.
// </copyright>

namespace WAF.Server
{
    using System;
    using System.Threading;
    using WAF.Server.Ipc;
    using System.Collections.Generic;

    /// <summary>
    /// Core functions and base class for the web server module
    /// Provides request handling and caching functions
    /// </summary>
    public class WebServerCore
    {
        /// <summary>
        /// Holds a unique id for this WebServer instance. No sync needed, because it won't change
        /// </summary>
        private Guid webServerID;

        /// <summary>
        /// Holds the current request number, sync over Interlocked.Increment
        /// </summary>
        private long requestNumber;

        /// <summary>
        /// Holds the pending requests, sync with pendingRequestsLock object;
        /// </summary>
        private Dictionary<ContentKey, RequestState> pendingRequests;

        /// <summary>
        /// The locking object for the pendingRequests dictionary;
        /// </summary>
        private object pendingRequestsLock;

        /// <summary>
        /// This delegate is used to send the request to the app server.
        /// </summary>
        private ProcessAppServerRequestDelegate processAppServerRequest;

        /// <summary>
        /// This delegate is used to process the recceived response on the native web server
        /// </summary>
        private ProcessNativeResponseDelegate processNativeResponse;

        public Guid WebServerID { get { return webServerID;  } }

        public bool BlockRequestThread { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="WebServerCore"/> class.
        /// </summary>
        /// <param name="processAppServerRequest">The delegate whitch sends requests to the app server</param>
        /// <param name="processNativeResponse">The delegate which processes the response on the native system </param>
        public void Init(ProcessAppServerRequestDelegate processAppServerRequest, ProcessNativeResponseDelegate processNativeResponse)
        {
            if (processAppServerRequest == null)
            {
                throw new ArgumentNullException("appServerRequestContentDelegate"); 
            }

            webServerID = Guid.NewGuid();
            requestNumber = 1;
            this.pendingRequests = new Dictionary<ContentKey, RequestState>();
            this.pendingRequestsLock = new object();

            this.processAppServerRequest = processAppServerRequest;
            this.processNativeResponse = processNativeResponse;
        }

        /// <summary>
        /// Delegate for content generation functions
        /// </summary>
        /// <param name="request">The request.</param>
        public delegate void ProcessAppServerRequestDelegate(ContentRequest request);

        /// <summary>
        /// Native response processing delegate. 
        /// </summary>
        /// <param name="response">The response.</param>
        /// <param name="nativeContext">The native context.</param>
        public delegate void ProcessNativeResponseDelegate(ContentResponse response, object nativeContext);


        /// <summary>
        /// Generates the content.
        /// </summary>
        /// <param name="request">The request data.</param>
        /// <param name="nativeContext">The native context.</param>
        public virtual void ProcessNativeRequest(ContentRequest request, object nativeContext)
        {   
            long requestNumber = Interlocked.Increment(ref this.requestNumber);
            request.Key = new ContentKey(webServerID,requestNumber);
            RequestState state = new RequestState();
            state.NatveContext = nativeContext;
            if (BlockRequestThread)
                state.BlockedThread = Thread.CurrentThread;

            lock (this.pendingRequestsLock)
            {
                pendingRequests.Add(request.Key, state);
            }
            
            processAppServerRequest(request);

            if (BlockRequestThread)
            {
                try
                {
                    Thread.Sleep(Timeout.Infinite);
                }
                catch (ThreadInterruptedException) { }

            }
        }

        /// <summary>
        /// Processes the app server response.
        /// </summary>
        /// <param name="response">The response.</param>
        public virtual void ProcessAppServerResponse(ContentResponse response)
        {
            RequestState requestState;
            lock (this.pendingRequestsLock)
            {
                requestState = pendingRequests[response.Key];
                pendingRequests.Remove(response.Key);
            }

            processNativeResponse(response, requestState.NatveContext);

            if (requestState.BlockedThread != null)
                requestState.BlockedThread.Interrupt();

        }

    }
}
